home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / tusrc.zip / SRC / CSPLIT.C < prev    next >
C/C++ Source or Header  |  1993-09-18  |  32KB  |  1,329 lines

  1. /* csplit - split a file into sections determined by context lines
  2.    Copyright (C) 1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by Stuart Kemp, cpsrk@groper.jcu.edu.au.
  19.    Modified by David MacKenzie, djm@gnu.ai.mit.edu. */
  20.  
  21. #include <stdio.h>
  22. #include "../lib/getopt.h"
  23. #include <sys/types.h>
  24. #include <signal.h>
  25. #include "../lib/regex.h"
  26. #include "system.h"
  27. #include "version.h"
  28. #include <io.h>
  29. #define SIGHUP      4
  30. #define SIGQUIT     9
  31.  
  32. #ifdef STDC_HEADERS
  33. #include <stdlib.h>
  34. #else
  35. char *malloc ();
  36. char *realloc ();
  37. #endif
  38.  
  39. void error ();
  40.  
  41.  
  42. static char *xrealloc ();
  43. static char *xmalloc ();
  44. static void cleanup ();
  45. static void close_output_file ();
  46. static void create_output_file ();
  47. static void save_line_to_file ();
  48. static void usage ();
  49.  
  50. #ifndef TRUE
  51. #define FALSE 0
  52. #define TRUE 1
  53. #endif
  54.  
  55. /* Increment size of area for control records. */
  56. #define ALLOC_SIZE 20
  57.  
  58. /* The default prefix for output file names. */
  59. #define DEFAULT_PREFIX    "xx"
  60.  
  61. typedef int boolean;
  62.  
  63. /* A compiled pattern arg. */
  64. struct control
  65. {
  66.   char *regexpr;        /* Non-compiled regular expression. */
  67.   struct re_pattern_buffer re_compiled;    /* Compiled regular expression. */
  68.   int offset;            /* Offset from regexp to split at. */
  69.   int lines_required;        /* Number of lines required. */
  70.   int repeat;            /* Repeat count. */
  71.   int argnum;            /* ARGV index. */
  72.   boolean ignore;        /* If true, produce no output (for regexp). */
  73. };
  74.  
  75. /* Initial size of data area in buffers. */
  76. #define START_SIZE    8191
  77.  
  78. /* Increment size for data area. */
  79. #define INCR_SIZE    2048
  80.  
  81. /* Number of lines kept in each node in line list. */
  82. #define CTRL_SIZE    80
  83.  
  84. #ifdef DEBUG
  85. /* Some small values to test the algorithms. */
  86. #define START_SIZE    200
  87. #define INCR_SIZE    10
  88. #define CTRL_SIZE    1
  89. #endif
  90.  
  91. /* A string with a length count. */
  92. struct cstring
  93. {
  94.   int len;
  95.   char *str;
  96. };
  97.  
  98. /* Pointers to the beginnings of lines in the buffer area.
  99.    These structures are linked together if needed. */
  100. struct line
  101. {
  102.   unsigned used;        /* Number of offsets used in this struct. */
  103.   unsigned insert_index;    /* Next offset to use when inserting line. */
  104.   unsigned retrieve_index;    /* Next index to use when retrieving line. */
  105.   struct cstring starts[CTRL_SIZE]; /* Lines in the data area. */
  106.   struct line *next;        /* Next in linked list. */
  107. };
  108.  
  109. /* The structure to hold the input lines.
  110.    Contains a pointer to the data area and a list containing
  111.    pointers to the individual lines. */
  112. struct buffer_record
  113. {
  114.   unsigned bytes_alloc;        /* Size of the buffer area. */
  115.   unsigned bytes_used;        /* Bytes used in the buffer area. */
  116.   unsigned start_line;        /* First line number in this buffer. */
  117.   unsigned first_available;    /* First line that can be retrieved. */
  118.   unsigned num_lines;        /* Number of complete lines in this buffer. */
  119.   char *buffer;            /* Data area. */
  120.   struct line *line_start;    /* Head of list of pointers to lines. */
  121.   struct line *curr_line;    /* The line start record currently in use. */
  122.   struct buffer_record *next;
  123. };
  124.  
  125. /* The name this program was run with. */
  126. char *program_name;
  127.  
  128. /* Input file descriptor. */
  129. static int input_desc = 0;
  130.  
  131. /* List of available buffers. */
  132. static struct buffer_record *free_list = NULL;
  133.  
  134. /* Start of buffer list. */
  135. static struct buffer_record *head = NULL;
  136.  
  137. /* Partially read line. */
  138. static char *hold_area = NULL;
  139.  
  140. /* Number of chars in `hold_area'. */
  141. static unsigned hold_count = 0;
  142.  
  143. /* Number of the last line in the buffers. */
  144. static unsigned last_line_number = 0;
  145.  
  146. /* Number of the line currently being examined. */
  147. static unsigned current_line = 0;
  148.  
  149. /* Number of the last line in the input file. */
  150. static unsigned last_line_in_file = 0;
  151.  
  152. /* If TRUE, we have read EOF. */
  153. static boolean have_read_eof = FALSE;
  154.  
  155. /* Name of output files. */
  156. static char *filename_space = NULL;
  157.  
  158. /* Prefix part of output file names. */
  159. static char *prefix = NULL;
  160.  
  161. /* Number of digits to use in output file names. */
  162. static int digits = 2;
  163.  
  164. /* Number of files created so far. */
  165. static unsigned files_created = 0;
  166.  
  167. /* Number of bytes written to current file. */
  168. static unsigned bytes_written;
  169.  
  170. /* Output file pointer. */
  171. static FILE *output_stream = NULL;
  172.  
  173. /* Perhaps it would be cleaner to pass arg values instead of indexes. */
  174. static char **global_argv;
  175.  
  176. /* If TRUE, do not print the count of bytes in each output file. */
  177. static boolean suppress_count;
  178.  
  179. /* If TRUE, remove output files on error. */
  180. static boolean remove_files;
  181.  
  182. /* The compiled pattern arguments, which determine how to split
  183.    the input file. */
  184. static struct control *controls;
  185.  
  186. /* Number of elements in `controls'. */
  187. static unsigned control_used;
  188.  
  189. /* If non-zero, display usage information and exit.  */
  190. static int flag_help;
  191.  
  192. /* If non-zero, print the version on standard error.  */
  193. static int flag_version;
  194.  
  195. static struct option const longopts[] =
  196. {
  197.   {"digits", required_argument, NULL, 'n'},
  198.   {"quiet", no_argument, NULL, 's'},
  199.   {"silent", no_argument, NULL, 's'},
  200.   {"keep-files", no_argument, NULL, 'k'},
  201.   {"prefix", required_argument, NULL, 'f'},
  202.   {"help", no_argument, &flag_help, 1},
  203.   {"version", no_argument, &flag_version, 1},
  204.   {NULL, 0, NULL, 0}
  205. };
  206.  
  207. /* Allocate N bytes of memory dynamically, with error checking.  */
  208.  
  209. static char *
  210. xmalloc (n)
  211.      unsigned n;
  212. {
  213.   char *p;
  214.  
  215.   p = malloc (n);
  216.   if (p == NULL)
  217.     {
  218.       error (0, 0, "virtual memory exhausted");
  219.       cleanup ();
  220.     }
  221.   return p;
  222. }
  223.  
  224. /* Change the size of an allocated block of memory P to N bytes,
  225.    with error checking.
  226.    If P is NULL, run xmalloc.
  227.    If N is 0, run free and return NULL.  */
  228.  
  229. static char *
  230. xrealloc (p, n)
  231.      char *p;
  232.      unsigned n;
  233. {
  234.   if (p == NULL)
  235.     return xmalloc (n);
  236.   if (n == 0)
  237.     {
  238.       free (p);
  239.       return 0;
  240.     }
  241.   p = realloc (p, n);
  242.   if (p == NULL)
  243.     {
  244.       error (0, 0, "virtual memory exhausted");
  245.       cleanup ();
  246.     }
  247.   return p;
  248. }
  249.  
  250. /* Keep track of NUM chars of a partial line in buffer START.
  251.    These chars will be retrieved later when another large buffer is read.
  252.    It is not necessary to create a new buffer for these chars; instead,
  253.    we keep a pointer to the existing buffer.  This buffer *is* on the
  254.    free list, and when the next buffer is obtained from this list
  255.    (even if it is this one), these chars will be placed at the
  256.    start of the new buffer. */
  257.  
  258. static void
  259. save_to_hold_area (start, num)
  260.      char *start;
  261.      unsigned num;
  262. {
  263.   hold_area = start;
  264.   hold_count = num;
  265. }
  266.  
  267. /* Read up to MAX chars from the input stream into DEST.
  268.    Return the number of chars read. */
  269.  
  270. static int
  271. read_input (dest, max)
  272.      char *dest;
  273.      unsigned max;
  274. {
  275.   int bytes_read;
  276.  
  277.   if (max == 0)
  278.     return 0;
  279.  
  280.   bytes_read = read (input_desc, dest, max);
  281.  
  282.   if (bytes_read == 0)
  283.     have_read_eof = TRUE;
  284.  
  285.   if (bytes_read < 0)
  286.     {
  287.       error (0, errno, "read error");
  288.       cleanup ();
  289.     }
  290.  
  291.   return bytes_read;
  292. }
  293.  
  294. /* Initialize existing line record P. */
  295.  
  296. static void
  297. clear_line_control (p)
  298.      struct line *p;
  299. {
  300.   p->used = 0;
  301.   p->insert_index = 0;
  302.   p->retrieve_index = 0;
  303. }
  304.  
  305. /* Initialize all line records in B. */
  306.  
  307. static void
  308. clear_all_line_control (b)
  309.      struct buffer_record *b;
  310. {
  311.   struct line *l;
  312.  
  313.   for (l = b->line_start; l; l = l->next)
  314.     clear_line_control (l);
  315. }
  316.  
  317. /* Return a new, initialized line record. */
  318.  
  319. static struct line *
  320. new_line_control ()
  321. {
  322.   struct line *p;
  323.  
  324.   p = (struct line *) xmalloc (sizeof (struct line));
  325.  
  326.   p->next = NULL;
  327.   clear_line_control (p);
  328.  
  329.   return p;
  330. }
  331.  
  332. /* Record LINE_START, which is the address of the start of a line
  333.    of length LINE_LEN in the large buffer, in the lines buffer of B. */
  334.  
  335. static void
  336. keep_new_line (b, line_start, line_len)
  337.      struct buffer_record *b;
  338.      char *line_start;
  339.      int line_len;
  340. {
  341.   struct line *l;
  342.  
  343.   /* If there is no existing area to keep line info, get some. */
  344.   if (b->line_start == NULL)
  345.     b->line_start = b->curr_line = new_line_control ();
  346.  
  347.   /* If existing area for lines is full, get more. */
  348.   if (b->curr_line->used == CTRL_SIZE)
  349.     {
  350.       b->curr_line->next = new_line_control ();
  351.       b->curr_line = b->curr_line->next;
  352.     }
  353.  
  354.   l = b->curr_line;
  355.  
  356.   /* Record the start of the line, and update counters. */
  357.   l->starts[l->insert_index].str = line_start;
  358.   l->starts[l->insert_index].len = line_len;
  359.   l->used++;
  360.   l->insert_index++;
  361. }
  362.  
  363. /* Scan the buffer in B for newline characters
  364.    and record the line start locations and lengths in B.
  365.    Return the number of lines found in this buffer.
  366.  
  367.    There may be an incomplete line at the end of the buffer;
  368.    a pointer is kept to this area, which will be used when
  369.    the next buffer is filled. */
  370.  
  371. static unsigned
  372. record_line_starts (b)
  373.      struct buffer_record *b;
  374. {
  375.   char *line_start;        /* Start of current line. */
  376.   char *line_end;        /* End of each line found. */
  377.   unsigned bytes_left;        /* Length of incomplete last line. */
  378.   unsigned lines;        /* Number of lines found. */
  379.   unsigned line_length;        /* Length of each line found. */
  380.  
  381.   if (b->bytes_used == 0)
  382.     return 0;
  383.  
  384.   lines = 0;
  385.   line_start = b->buffer;
  386.   bytes_left = b->bytes_used;
  387.  
  388.   for (;;)
  389.     {
  390.       line_end = memchr (line_start, '\n', bytes_left);
  391.       if (line_end == NULL)
  392.     break;
  393.       line_length = line_end - line_start + 1;
  394.       keep_new_line (b, line_start, line_length);
  395.       bytes_left -= line_length;
  396.       line_start = line_end + 1;
  397.       lines++;
  398.     }
  399.  
  400.   /* Check for an incomplete last line. */
  401.   if (bytes_left)
  402.     {
  403.       if (have_read_eof)
  404.     {
  405.       keep_new_line (b, line_start, bytes_left);
  406.       lines++;
  407.       last_line_in_file = last_line_number + lines;
  408.     }
  409.       else
  410.     save_to_hold_area (line_start, bytes_left);
  411.     }
  412.  
  413.   b->num_lines = lines;
  414.   b->first_available = b->start_line = last_line_number + 1;
  415.   last_line_number += lines;
  416.  
  417.   return lines;
  418. }
  419.  
  420. /* Return a new buffer with room to store SIZE bytes, plus
  421.    an extra byte for safety. */
  422.  
  423. static struct buffer_record *
  424. create_new_buffer (size)
  425.      unsigned size;
  426. {
  427.   struct buffer_record *new_buffer;
  428.  
  429.   new_buffer = (struct buffer_record *)
  430.     xmalloc (sizeof (struct buffer_record));
  431.  
  432.   new_buffer->buffer = (char *) xmalloc (size + 1);
  433.  
  434.   new_buffer->bytes_alloc = size;
  435.   new_buffer->line_start = new_buffer->curr_line = NULL;
  436.  
  437.   return new_buffer;
  438. }
  439.  
  440. /* Return a new buffer of at least MINSIZE bytes.  If a buffer of at
  441.    least that size is currently free, use it, otherwise create a new one. */
  442.  
  443. static struct buffer_record *
  444. get_new_buffer (min_size)
  445.      unsigned min_size;
  446. {
  447.   struct buffer_record *p, *q;
  448.   struct buffer_record *new_buffer; /* Buffer to return. */
  449.   unsigned alloc_size;        /* Actual size that will be requested. */
  450.  
  451.   alloc_size = START_SIZE;
  452.   while (min_size > alloc_size)
  453.     alloc_size += INCR_SIZE;
  454.  
  455.   if (free_list == NULL)
  456.     new_buffer = create_new_buffer (alloc_size);
  457.   else
  458.     {
  459.       /* Use first-fit to find a buffer. */
  460.       p = new_buffer = NULL;
  461.       q = free_list;
  462.  
  463.       do
  464.     {
  465.       if (q->bytes_alloc >= min_size)
  466.         {
  467.           if (p == NULL)
  468.         free_list = q->next;
  469.           else
  470.         p->next = q->next;
  471.           break;
  472.         }
  473.       p = q;
  474.       q = q->next;
  475.     }
  476.       while (q);
  477.  
  478.       new_buffer = (q ? q : create_new_buffer (alloc_size));
  479.  
  480.       new_buffer->curr_line = new_buffer->line_start;
  481.       clear_all_line_control (new_buffer);
  482.     }
  483.  
  484.   new_buffer->num_lines = 0;
  485.   new_buffer->bytes_used = 0;
  486.   new_buffer->start_line = new_buffer->first_available = last_line_number + 1;
  487.   new_buffer->next = NULL;
  488.  
  489.   return new_buffer;
  490. }
  491.  
  492. /* Add buffer BUF to the list of free buffers. */
  493.  
  494. static void
  495. free_buffer (buf)
  496.      struct buffer_record *buf;
  497. {
  498.   buf->next = free_list;
  499.   free_list = buf;
  500. }
  501.  
  502. /* Append buffer BUF to the linked list of buffers that contain
  503.    some data yet to be processed. */
  504.  
  505. static void
  506. save_buffer (buf)
  507.      struct buffer_record *buf;
  508. {
  509.   struct buffer_record *p;
  510.  
  511.   buf->next = NULL;
  512.   buf->curr_line = buf->line_start;
  513.  
  514.   if (head == NULL)
  515.     head = buf;
  516.   else
  517.     {
  518.       for (p = head; p->next; p = p->next)
  519.     /* Do nothing. */ ;
  520.       p->next = buf;
  521.     }
  522. }
  523.  
  524. /* Fill a buffer of input.
  525.  
  526.    Set the initial size of the buffer to a default.
  527.    Fill the buffer (from the hold area and input stream)
  528.    and find the individual lines.
  529.    If no lines are found (the buffer is too small to hold the next line),
  530.    release the current buffer (whose contents would have been put in the
  531.    hold area) and repeat the process with another large buffer until at least
  532.    one entire line has been read.
  533.  
  534.    Return TRUE if a new buffer was obtained, otherwise false
  535.    (in which case end-of-file must have been encountered). */
  536.  
  537. static boolean
  538. load_buffer ()
  539. {
  540.   struct buffer_record *b;
  541.   unsigned bytes_wanted = START_SIZE; /* Minimum buffer size. */
  542.   unsigned bytes_avail;        /* Size of new buffer created. */
  543.   unsigned lines_found;        /* Number of lines in this new buffer. */
  544.   char *p;            /* Place to load into buffer. */
  545.  
  546.   if (have_read_eof)
  547.     return FALSE;
  548.  
  549.   /* We must make the buffer at least as large as the amount of data
  550.      in the partial line left over from the last call. */
  551.   if (bytes_wanted < hold_count)
  552.     bytes_wanted = hold_count;
  553.  
  554.   do
  555.     {
  556.       b = get_new_buffer (bytes_wanted);
  557.       bytes_avail = b->bytes_alloc; /* Size of buffer returned. */
  558.       p = b->buffer;
  559.  
  560.       /* First check the `holding' area for a partial line. */
  561.       if (hold_count)
  562.     {
  563.       if (p != hold_area)
  564.         bcopy (hold_area, p, hold_count);
  565.       p += hold_count;
  566.       b->bytes_used += hold_count;
  567.       bytes_avail -= hold_count;
  568.       hold_count = 0;
  569.     }
  570.  
  571.       b->bytes_used += (unsigned) read_input (p, bytes_avail);
  572.  
  573.       lines_found = record_line_starts (b);
  574.       bytes_wanted = b->bytes_alloc + INCR_SIZE;
  575.       if (!lines_found)
  576.     free_buffer (b);
  577.     }
  578.   while (!lines_found && !have_read_eof);
  579.  
  580.   if (lines_found)
  581.     save_buffer (b);
  582.  
  583.   return lines_found != 0;
  584. }
  585.  
  586. /* Return the line number of the first line that has not yet been retrieved. */
  587.  
  588. static unsigned
  589. get_first_line_in_buffer ()
  590. {
  591.   if (head == NULL && !load_buffer ())
  592.     error (1, errno, "input disappeared");
  593.  
  594.   return head->first_available;
  595. }
  596.  
  597. /* Return a pointer to the logical first line in the buffer and make the 
  598.    next line the logical first line.
  599.    Return NULL if there is no more input. */
  600.  
  601. static struct cstring *
  602. remove_line ()
  603. {
  604.   struct cstring *line;        /* Return value. */
  605.   struct line *l;        /* For convenience. */
  606.  
  607.   if (head == NULL && !load_buffer ())
  608.     return NULL;
  609.  
  610.   if (current_line < head->first_available)
  611.     current_line = head->first_available;
  612.  
  613.   ++(head->first_available);
  614.  
  615.   l = head->curr_line;
  616.  
  617.   line = &l->starts[l->retrieve_index];
  618.  
  619.   /* Advance index to next line. */
  620.   if (++l->retrieve_index == l->used)
  621.     {
  622.       /* Go on to the next line record. */
  623.       head->curr_line = l->next;
  624.       if (head->curr_line == NULL || head->curr_line->used == 0)
  625.     {
  626.       /* Go on to the next data block. */
  627.       struct buffer_record *b = head;
  628.       head = head->next;
  629.       free_buffer (b);
  630.     }
  631.     }
  632.  
  633.   return line;
  634. }
  635.  
  636. /* Search the buffers for line LINENUM, reading more input if necessary.
  637.    Return a pointer to the line, or NULL if it is not found in the file. */
  638.  
  639. static struct cstring *
  640. find_line (linenum)
  641.      unsigned linenum;
  642. {
  643.   struct buffer_record *b;
  644.  
  645.   if (head == NULL && !load_buffer ())
  646.     return NULL;
  647.  
  648.   if (linenum < head->start_line)
  649.     return NULL;
  650.  
  651.   for (b = head;;)
  652.     {
  653.       if (linenum < b->start_line + b->num_lines)
  654.     {
  655.       /* The line is in this buffer. */
  656.       struct line *l;
  657.       unsigned offset;    /* How far into the buffer the line is. */
  658.  
  659.       l = b->line_start;
  660.       offset = linenum - b->start_line;
  661.       /* Find the control record. */
  662.       while (offset >= CTRL_SIZE)
  663.         {
  664.           l = l->next;
  665.           offset -= CTRL_SIZE;
  666.         }
  667.       return &l->starts[offset];
  668.     }
  669.       if (b->next == NULL && !load_buffer ())
  670.     return NULL;
  671.       b = b->next;        /* Try the next data block. */
  672.     }
  673. }
  674.  
  675. /* Return TRUE if at least one more line is available for input. */
  676.  
  677. static boolean
  678. no_more_lines ()
  679. {
  680.   return (find_line (current_line + 1) == NULL) ? TRUE : FALSE;
  681. }
  682.  
  683. /* Set the name of the input file to NAME and open it. */
  684.  
  685. static void
  686. set_input_file (name)
  687.      char *name;
  688. {
  689.   if (!strcmp (name, "-"))
  690.     input_desc = 0;
  691.   else
  692.     {
  693.       input_desc = open (name, O_RDONLY);
  694.       if (input_desc < 0)
  695.     error (1, errno, "%s", name);
  696.     }
  697. }
  698.  
  699. /* Write all lines from the beginning of the buffer up to, but
  700.    not including, line LAST_LINE, to the current output file.
  701.    If IGNORE is TRUE, do not output lines selected here.
  702.    ARGNUM is the index in ARGV of the current pattern. */
  703.  
  704. static void
  705. write_to_file (last_line, ignore, argnum)
  706.      unsigned last_line;
  707.      boolean ignore;
  708.      int argnum;
  709. {
  710.   struct cstring *line;
  711.   unsigned first_line;        /* First available input line. */
  712.   unsigned lines;        /* Number of lines to output. */
  713.   unsigned i;
  714.  
  715.   first_line = get_first_line_in_buffer ();
  716.  
  717.   if (first_line > last_line)
  718.     {
  719.       error (0, 0, "%s: line number out of range", global_argv[argnum]);
  720.       cleanup ();
  721.     }
  722.  
  723.   lines = last_line - first_line;
  724.  
  725.   for (i = 0; i < lines; i++)
  726.     {
  727.       line = remove_line ();
  728.       if (line == NULL)
  729.     {
  730.       error (0, 0, "%s: line number out of range", global_argv[argnum]);
  731.       cleanup ();
  732.     }
  733.       if (!ignore)
  734.     save_line_to_file (line);
  735.     }
  736. }
  737.  
  738. /* Output any lines left after all regexps have been processed. */
  739.  
  740. static void
  741. dump_rest_of_file ()
  742. {
  743.   struct cstring *line;
  744.  
  745.   while ((line = remove_line ()) != NULL)
  746.     save_line_to_file (line);
  747. }
  748.  
  749. /* Handle an attempt to read beyond EOF under the control of record P,
  750.    on iteration REPETITION if nonzero. */
  751.  
  752. static void
  753. handle_line_error (p, repetition)
  754.      struct control *p;
  755.      int repetition;
  756. {
  757.   fprintf (stderr, "%s: `%d': line number out of range",
  758.        program_name, p->lines_required);
  759.   if (repetition)
  760.     fprintf (stderr, " on repetition %d\n", repetition);
  761.   else
  762.     fprintf (stderr, "\n");
  763.  
  764.   cleanup ();
  765. }
  766.  
  767. /* Determine the line number that marks the end of this file,
  768.    then get those lines and save them to the output file.
  769.    P is the control record.
  770.    REPETITION is the repetition number. */
  771.  
  772. static void
  773. process_line_count (p, repetition)
  774.      struct control *p;
  775.      int repetition;
  776. {
  777.   unsigned linenum;
  778.   unsigned last_line_to_save = p->lines_required * (repetition + 1);
  779.   struct cstring *line;
  780.  
  781.   create_output_file ();
  782.  
  783.   linenum = get_first_line_in_buffer ();
  784.  
  785.   /* Check for requesting a line that has already been written out.
  786.      If this ever happens, it's due to a bug in csplit. */
  787.   if (linenum >= last_line_to_save)
  788.     handle_line_error (p, repetition);
  789.  
  790.   while (linenum++ < last_line_to_save)
  791.     {
  792.       line = remove_line ();
  793.       if (line == NULL)
  794.     handle_line_error (p, repetition);
  795.       save_line_to_file (line);
  796.     }
  797.  
  798.   close_output_file ();
  799.  
  800.   /* Ensure that the line number specified is not 1 greater than
  801.      the number of lines in the file. */
  802.   if (no_more_lines ())
  803.     handle_line_error (p, repetition);
  804. }
  805.  
  806. static void
  807. regexp_error (p, repetition, ignore)
  808.      struct control *p;
  809.      int repetition;
  810.      boolean ignore;
  811. {
  812.   fprintf (stderr, "%s: `%s': match not found",
  813.        program_name, global_argv[p->argnum]);
  814.  
  815.   if (repetition)
  816.     fprintf (stderr, " on repetition %d\n", repetition);
  817.   else
  818.     fprintf (stderr, "\n");
  819.  
  820.   if (!ignore)
  821.     {
  822.       dump_rest_of_file ();
  823.       close_output_file ();
  824.     }
  825.   cleanup ();
  826. }
  827.  
  828. /* Read the input until a line matches the regexp in P, outputting
  829.    it unless P->IGNORE is TRUE.
  830.    REPETITION is this repeat-count; 0 means the first time. */
  831.  
  832. static void
  833. process_regexp (p, repetition)
  834.      struct control *p;
  835.      int repetition;
  836. {
  837.   struct cstring *line;        /* From input file. */
  838.   register unsigned line_len;    /* To make "$" in regexps work. */
  839.   unsigned break_line;        /* First line number of next file. */
  840.   boolean ignore = p->ignore;    /* If TRUE, skip this section. */
  841.   int ret;
  842.  
  843.   if (!ignore)
  844.     create_output_file ();
  845.  
  846.   /* If there is no offset for the regular expression, or
  847.      it is positive, then it is not necessary to buffer the lines. */
  848.  
  849.   if (p->offset >= 0)
  850.     {
  851.       for (;;)
  852.     {
  853.       line = find_line (++current_line);
  854.       if (line == NULL)
  855.         regexp_error (p, repetition, ignore);
  856.       line_len = line->len;
  857.       if (line->str[line_len - 1] == '\n')
  858.         line_len--;
  859.       ret = re_search (&p->re_compiled, line->str, line_len,
  860.                0, line_len, (struct re_registers *) 0);
  861.       if (ret == -2)
  862.         {
  863.           error (0, 0, "error in regular expression search");
  864.           cleanup ();
  865.         }
  866.       if (ret == -1)
  867.         {
  868.           line = remove_line ();
  869.           if (!ignore)
  870.         save_line_to_file (line);
  871.         }
  872.       else
  873.         break;
  874.     }
  875.     }
  876.   else
  877.     {
  878.       /* Buffer the lines. */
  879.       for (;;)
  880.     {
  881.       line = find_line (++current_line);
  882.       if (line == NULL)
  883.         regexp_error (p, repetition, ignore);
  884.       line_len = line->len;
  885.       if (line->str[line_len - 1] == '\n')
  886.         line_len--;
  887.       ret = re_search (&p->re_compiled, line->str, line_len,
  888.                0, line_len, (struct re_registers *) 0);
  889.       if (ret == -2)
  890.         {
  891.           error (0, 0, "error in regular expression search");
  892.           cleanup ();
  893.         }
  894.       if (ret >= 0)
  895.         break;
  896.     }
  897.     }
  898.  
  899.   /* Account for any offset from this regexp. */
  900.   break_line = current_line + p->offset;
  901.  
  902.   write_to_file (break_line, ignore, p->argnum);
  903.  
  904.   if (!ignore)
  905.     close_output_file ();
  906.  
  907.   current_line = break_line;
  908. }
  909.  
  910. /* Split the input file according to the control records we have built. */
  911.  
  912. static void
  913. split_file ()
  914. {
  915.   register int i, j;
  916.  
  917.   for (i = 0; (unsigned) i < control_used; i++)
  918.     {
  919.       if (controls[i].regexpr)
  920.     {
  921.       for (j = 0; j <= controls[i].repeat; j++)
  922.         process_regexp (&controls[i], j);
  923.     }
  924.       else
  925.     {
  926.       for (j = 0; j <= controls[i].repeat; j++)
  927.         process_line_count (&controls[i], j);
  928.     }
  929.     }
  930.  
  931.   create_output_file ();
  932.   dump_rest_of_file ();
  933.   close_output_file ();
  934. }
  935.  
  936. /* Return the name of output file number NUM. */
  937.  
  938. static char *
  939. make_filename (num)
  940.      int num;
  941. {
  942.   sprintf (filename_space, "%s%0*d", prefix, digits, num);
  943.   return filename_space;
  944. }
  945.  
  946. /* Create the next output file. */
  947.  
  948. static void
  949. create_output_file ()
  950. {
  951.   char *name;
  952.  
  953.   name = make_filename (files_created);
  954.   output_stream = fopen (name, "w");
  955.   if (output_stream == NULL)
  956.     {
  957.       error (0, errno, "%s", name);
  958.       cleanup ();
  959.     }
  960.   files_created++;
  961.   bytes_written = 0;
  962. }
  963.  
  964. /* Delete all the files we have created. */
  965.  
  966. static void
  967. delete_all_files ()
  968. {
  969.   int i;
  970.   char *name;
  971.  
  972.   for (i = 0; (unsigned) i < files_created; i++)
  973.     {
  974.       name = make_filename (i);
  975.       if (unlink (name))
  976.     error (0, errno, "%s", name);
  977.     }
  978. }
  979.  
  980. /* Close the current output file and print the count
  981.    of characters in this file. */
  982.  
  983. static void
  984. close_output_file ()
  985. {
  986.   if (output_stream)
  987.     {
  988.       if (fclose (output_stream) == EOF)
  989.     {
  990.       error (0, errno, "write error");
  991.       cleanup ();
  992.     }
  993.       if (!suppress_count)
  994.     fprintf (stdout, "%d\n", bytes_written);
  995.       output_stream = NULL;
  996.     }
  997. }
  998.  
  999. /* Optionally remove files created so far; then exit.
  1000.    Called when an error detected. */
  1001.  
  1002. static void
  1003. cleanup ()
  1004. {
  1005.   if (output_stream)
  1006.     close_output_file ();
  1007.  
  1008.   if (remove_files)
  1009.     delete_all_files ();
  1010.  
  1011.   exit (1);
  1012. }
  1013.  
  1014. /* Save line LINE to the output file and
  1015.    increment the character count for the current file. */
  1016.  
  1017. static void
  1018. save_line_to_file (line)
  1019.      struct cstring *line;
  1020. {
  1021.   fwrite (line->str, sizeof (char), line->len, output_stream);
  1022.   bytes_written += line->len;
  1023. }
  1024.  
  1025. /* Return a new, initialized control record. */
  1026.  
  1027. static struct control *
  1028. new_control_record ()
  1029. {
  1030.   static unsigned control_allocated = 0; /* Total space allocated. */
  1031.   register struct control *p;
  1032.  
  1033.   if (control_allocated == 0)
  1034.     {
  1035.       control_allocated = ALLOC_SIZE;
  1036.       controls = (struct control *)
  1037.     xmalloc (sizeof (struct control) * control_allocated);
  1038.     }
  1039.   else if (control_used == control_allocated)
  1040.     {
  1041.       control_allocated += ALLOC_SIZE;
  1042.       controls = (struct control *)
  1043.     xrealloc (controls, sizeof (struct control) * control_allocated);
  1044.     }
  1045.   p = &controls[control_used++];
  1046.   p->regexpr = NULL;
  1047.   p->repeat = 0;
  1048.   p->lines_required = 0;
  1049.   p->offset = 0;
  1050.   return p;
  1051. }
  1052.  
  1053. /* Convert string NUM to an integer and put the value in *RESULT.
  1054.    Return a TRUE if the string consists entirely of digits,
  1055.    FALSE if not. */
  1056.  
  1057. static boolean
  1058. string_to_number (result, num)
  1059.      int *result;
  1060.      char *num;
  1061. {
  1062.   register char ch;
  1063.   register int val = 0;
  1064.  
  1065.   if (*num == '\0')
  1066.     return FALSE;
  1067.  
  1068.   while ((ch = *num++))
  1069.     {
  1070.       if (!ISDIGIT (ch))
  1071.     return FALSE;
  1072.       val = val * 10 + ch - '0';
  1073.     }
  1074.  
  1075.   *result = val;
  1076.   return TRUE;
  1077. }
  1078.  
  1079. /* Check if there is a numeric offset after a regular expression.
  1080.    STR is the entire command line argument.
  1081.    P is the control record for this regular expression.
  1082.    NUM is the numeric part of STR. */
  1083.  
  1084. static void
  1085. check_for_offset (p, str, num)
  1086.      struct control *p;
  1087.      char *str;
  1088.      char *num;
  1089. {
  1090.   if (*num != '-' && *num != '+')
  1091.     error (1, 0, "%s: `+' or `-' expected after delimeter", str);
  1092.  
  1093.   if (!string_to_number (&p->offset, num + 1))
  1094.     error (1, 0, "%s: integer expected after `%c'", str, *num);
  1095.  
  1096.   if (*num == '-')
  1097.     p->offset = -p->offset;
  1098. }
  1099.  
  1100. /* Given that the first character of command line arg STR is '{',
  1101.    make sure that the rest of the string is a valid repeat count
  1102.    and store its value in P.
  1103.    ARGNUM is the ARGV index of STR. */
  1104.  
  1105. static void
  1106. parse_repeat_count (argnum, p, str)
  1107.      int argnum;
  1108.      struct control *p;
  1109.      char *str;
  1110. {
  1111.   char *end;
  1112.  
  1113.   end = str + strlen (str) - 1;
  1114.   if (*end != '}')
  1115.     error (1, 0, "%s: `}' is required in repeat count", str);
  1116.   *end = '\0';
  1117.  
  1118.   if (!string_to_number (&p->repeat, str +  1))
  1119.     error (1, 0, "%s}: integer required between `{' and `}'",
  1120.        global_argv[argnum]);
  1121.  
  1122.   *end = '}';
  1123. }
  1124.  
  1125. /* Extract the regular expression from STR and check for a numeric offset.
  1126.    STR should start with the regexp delimiter character.
  1127.    Return a new control record for the regular expression.
  1128.    ARGNUM is the ARGV index of STR.
  1129.    Unless IGNORE is TRUE, mark these lines for output. */
  1130.  
  1131. static struct control *
  1132. extract_regexp (argnum, ignore, str)
  1133.      int argnum;
  1134.      boolean ignore;
  1135.      char *str;
  1136. {
  1137.   int len;            /* Number of chars in this regexp. */
  1138.   char delim = *str;
  1139.   char *closing_delim;
  1140.   struct control *p;
  1141.   const char *err;
  1142.  
  1143.   closing_delim = rindex (str + 1, delim);
  1144.   if (closing_delim == NULL)
  1145.     error (1, 0, "%s: closing delimeter `%c' missing", str, delim);
  1146.  
  1147.   len = closing_delim - str - 1;
  1148.   p = new_control_record ();
  1149.   p->argnum = argnum;
  1150.   p->ignore = ignore;
  1151.  
  1152.   p->regexpr = (char *) xmalloc ((unsigned) (len + 1));
  1153.   strncpy (p->regexpr, str + 1, len);
  1154.   p->re_compiled.allocated = len * 2;
  1155.   p->re_compiled.buffer = (unsigned char *) xmalloc (p->re_compiled.allocated);
  1156.   p->re_compiled.fastmap = xmalloc (256);
  1157.   p->re_compiled.translate = 0;
  1158.   err = re_compile_pattern (p->regexpr, len, &p->re_compiled);
  1159.   if (err)
  1160.     {
  1161.       error (0, 0, "%s: invalid regular expression: %s", str, err);
  1162.       cleanup ();
  1163.     }
  1164.  
  1165.   if (closing_delim[1])
  1166.     check_for_offset (p, str, closing_delim + 1);
  1167.  
  1168.   return p;
  1169. }
  1170.  
  1171. /* Extract the break patterns from args START through ARGC - 1 of ARGV.
  1172.    After each pattern, check if the next argument is a repeat count. */
  1173.  
  1174. static void
  1175. parse_patterns (argc, start, argv)
  1176.      int argc;
  1177.      int start;
  1178.      char **argv;
  1179. {
  1180.   int i;            /* Index into ARGV. */
  1181.   struct control *p;        /* New control record created. */
  1182.  
  1183.   for (i = start; i < argc; i++)
  1184.     {
  1185.       if (*argv[i] == '/' || *argv[i] == '%')
  1186.     {
  1187.       p = extract_regexp (i, *argv[i] == '%', argv[i]);
  1188.     }
  1189.       else
  1190.     {
  1191.       p = new_control_record ();
  1192.       p->argnum = i;
  1193.       if (!string_to_number (&p->lines_required, argv[i]))
  1194.         error (1, 0, "%s: invalid pattern", argv[i]);
  1195.     }
  1196.  
  1197.       if (i + 1 < argc && *argv[i + 1] == '{')
  1198.     {
  1199.       /* We have a repeat count. */
  1200.       i++;
  1201.       parse_repeat_count (i, p, argv[i]);
  1202.     }
  1203.     }
  1204. }
  1205.  
  1206. static void
  1207. interrupt_handler ()
  1208. {
  1209.   error (0, 0, "interrupted");
  1210.   cleanup ();
  1211. }
  1212.  
  1213. void
  1214. main (argc, argv)
  1215.      int argc;
  1216.      char **argv;
  1217. {
  1218.   int optc;
  1219. #ifdef _POSIX_VERSION
  1220.   struct sigaction oldact, newact;
  1221. #endif                /* _POSIX_VERSION */
  1222.  
  1223.   program_name = argv[0];
  1224.   global_argv = argv;
  1225.   controls = NULL;
  1226.   control_used = 0;
  1227.   suppress_count = FALSE;
  1228.   remove_files = TRUE;
  1229.   prefix = DEFAULT_PREFIX;
  1230.  
  1231. #ifdef _POSIX_VERSION
  1232.   newact.sa_handler = interrupt_handler;
  1233.   sigemptyset (&newact.sa_mask);
  1234.   newact.sa_flags = 0;
  1235.  
  1236.   sigaction (SIGHUP, NULL, &oldact);
  1237.   if (oldact.sa_handler != SIG_IGN)
  1238.     sigaction (SIGHUP, &newact, NULL);
  1239.  
  1240.   sigaction (SIGINT, NULL, &oldact);
  1241.   if (oldact.sa_handler != SIG_IGN)
  1242.     sigaction (SIGINT, &newact, NULL);
  1243.  
  1244.   sigaction (SIGQUIT, NULL, &oldact);
  1245.   if (oldact.sa_handler != SIG_IGN)
  1246.     sigaction (SIGQUIT, &newact, NULL);
  1247.  
  1248.   sigaction (SIGTERM, NULL, &oldact);
  1249.   if (oldact.sa_handler != SIG_IGN)
  1250.     sigaction (SIGTERM, &newact, NULL);
  1251. #else                /* !_POSIX_VERSION */
  1252.   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
  1253.     signal (SIGHUP, (void *) interrupt_handler);
  1254.   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
  1255.     signal (SIGINT, (void *) interrupt_handler);
  1256.   if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
  1257.     signal (SIGQUIT, (void *) interrupt_handler);
  1258.   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
  1259.     signal (SIGTERM, (void *) interrupt_handler);
  1260. #endif
  1261.  
  1262.   while ((optc = getopt_long (argc, argv, "f:kn:s", longopts, (int *) 0))
  1263.      != EOF)
  1264.     switch (optc)
  1265.       {
  1266.       case 0:
  1267.     break;
  1268.  
  1269.       case 'f':
  1270.     prefix = optarg;
  1271.     break;
  1272.  
  1273.       case 'k':
  1274.     remove_files = FALSE;
  1275.     break;
  1276.  
  1277.       case 'n':
  1278.     if (!string_to_number (&digits, optarg))
  1279.       error (1, 0, "%s: invalid number", optarg);
  1280.     break;
  1281.  
  1282.       case 's':
  1283.     suppress_count = TRUE;
  1284.     break;
  1285.  
  1286.       default:
  1287.     usage ();
  1288.       }
  1289.  
  1290.   if (flag_version)
  1291.     {
  1292.       fprintf (stderr, "%s\n", version_string);
  1293.       exit (0);
  1294.     }
  1295.  
  1296.   if (flag_help)
  1297.     usage ();
  1298.  
  1299.   if (optind >= argc - 1)
  1300.     usage ();
  1301.  
  1302.   filename_space = (char *) xmalloc (strlen (prefix) + digits + 2);
  1303.  
  1304.   set_input_file (argv[optind++]);
  1305.  
  1306.   parse_patterns (argc, optind, argv);
  1307.  
  1308.   split_file ();
  1309.  
  1310.   if (close (input_desc) < 0)
  1311.     {
  1312.       error (0, errno, "read error");
  1313.       cleanup ();
  1314.     }
  1315.  
  1316.   exit (0);
  1317. }
  1318.  
  1319. static void
  1320. usage ()
  1321. {
  1322.   fprintf (stderr, "\
  1323. Usage: %s [-sk] [-f prefix] [-n digits] [--prefix=prefix]\n\
  1324.        [--digits=digits] [--quiet] [--silent] [--keep-files]\n\
  1325.        [--help] [--version] file pattern...\n",
  1326.        program_name);
  1327.   exit (1);
  1328. }
  1329.